/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_interpret_StackOfNames_interface
#define simodo_interpret_StackOfNames_interface

/*! \file StackOfNames_interface.h
    \brief Интерфейс держателя семантических правил
*/

#include "simodo/variable/Variable.h"
#include "simodo/variable/FunctionWrapper.h"

#include <memory>
#include <vector>
#include <string>
#include <limits>

namespace simodo::interpret
{
    typedef size_t name_index_t;
    typedef size_t boundary_index_t;
    typedef uint16_t boundary_mark_t;

    inline const name_index_t     UNDEFINED_NAME_INDEX          = std::numeric_limits<name_index_t>::max();
    inline const boundary_index_t UNDEFINED_BOUNDARY_INDEX      = std::numeric_limits<boundary_index_t>::max();

    inline const boundary_mark_t  UNMARKED_BOUNDARY             = 0;
    inline const boundary_mark_t  BOUNDARY_MARK_MODULE_FRAME    = 1;
    inline const boundary_mark_t  BOUNDARY_MARK_FUNCTION_FRAME  = 2;
    inline const boundary_mark_t  BOUNDARY_MARK_CYCLE_FRAME     = 3;
    inline const boundary_mark_t  BOUNDARY_USER_MARK            = 10;

    inline const size_t           DEFAULT_VARIABLE_STACK_SIZE   = 1000;

    enum class BoundScope
    {
        Local,
        Global,
    };

    /*!
     * \brief The StackOfNames_interface class
     */
    class StackOfNames_interface
    {
    public:
        virtual ~StackOfNames_interface() = default;

        virtual name_index_t                push(const variable::Variable & name) = 0;
        virtual name_index_t                pushRef(const variable::Variable & v, 
                                                    const inout::TokenLocation & location, 
                                                    const variable::VariableSet_t & spec = {}) = 0;
        virtual name_index_t                top(size_t depth=0) const = 0;
        virtual name_index_t                index_over_top() const = 0;
        virtual void                        pop(size_t depth=1) = 0;
        virtual void                        erase(name_index_t name_index) = 0;

        virtual name_index_t                find(const std::u16string & name, BoundScope scope=BoundScope::Global) const = 0;
        virtual variable::Variable &        variable(name_index_t name_index) = 0;
        virtual const variable::Variable &  variable(name_index_t name_index) const = 0;
        virtual void                        setName(name_index_t name_index, const std::u16string & new_name) = 0;
        virtual bool                        addGlobal(name_index_t name_index) = 0;

        virtual boundary_index_t            startBoundary(BoundScope type=BoundScope::Local, boundary_mark_t mark=UNMARKED_BOUNDARY) = 0;
        virtual void                        setBoundaryToGlobal(boundary_index_t bound_index) = 0;
        virtual bool                        clearBoundary(boundary_index_t bound_index) = 0;
        virtual std::pair<name_index_t,name_index_t>
                                            boundaryLowAndTop(boundary_index_t bound_index) const = 0;
        virtual boundary_index_t            findNearestMarkedBoundary(boundary_mark_t mark, BoundScope type=BoundScope::Local) const = 0;
        virtual std::pair<boundary_mark_t,BoundScope> getTopBoundaryMarkAndScope() const = 0;     
        virtual variable::Variable &        accumulator() = 0;

        virtual variable::VariableSetWrapper_mutable
                                            makeVariableSetWrapper() = 0;
        virtual std::shared_ptr<variable::Object> 
                                            convertToObject(boundary_index_t bound_index) = 0;
        virtual void                        fillFromObject(std::shared_ptr<variable::Object> obj) = 0;
        virtual const std::vector<name_index_t> & globals() const = 0;

        virtual bool                        isRecursiveCalls() const = 0;

        virtual std::vector<boundary_index_t> getFunctionBounds() const = 0;
        virtual std::vector<name_index_t>   getFrameLocals(boundary_index_t frame_index) const = 0;
    };

}

#endif // simodo_interpret_StackOfNames_interface
